Improve exceptions handling in WLED#171646
Conversation
… in WLED integration Add proper exception handling for the new exception types introduced in wled library, with differentiated translation keys for invalid response errors and connection errors. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
|
Hey there @frenck, mind taking a look at this pull request as it has been labeled with an integration ( Code owner commandsCode owners of
|
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds more granular WLED error handling (invalid/empty responses and upgrade failures) and aligns tests/translations with the new behavior.
Changes:
- Add translation keys/messages for invalid responses (including presets-specific) and firmware install failures.
- Update coordinator/helpers/config flow/update flows to raise translated
HomeAssistantError/UpdateFailedfor new WLED exception types. - Extend WLED component tests to cover the new error scenarios and state behavior.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/components/wled/test_update.py | Updates update-install error test to assert translated HomeAssistantError for upgrade failures. |
| tests/components/wled/test_switch.py | Adds invalid-response handling tests ensuring entity does not become unavailable; adjusts call counts. |
| tests/components/wled/test_select.py | Adds invalid-response handling tests ensuring entity does not become unavailable; adjusts call counts. |
| tests/components/wled/test_number.py | Adds invalid-response test for number service calls and availability behavior. |
| tests/components/wled/test_light.py | Expands parametrized coverage to include invalid/empty response errors (presets vs full). |
| tests/components/wled/test_coordinator.py | Consolidates setup-failure tests into a parametrized suite covering more exceptions + log messages. |
| tests/components/wled/test_config_flow.py | Adds config-flow coverage for invalid/empty response errors and consolidates zeroconf abort tests. |
| tests/components/wled/test_button.py | Expands restart button error coverage and adds assertion for reset call. |
| homeassistant/components/wled/update.py | Converts WLEDUpgradeError into translated HomeAssistantError and refreshes coordinator after install attempt. |
| homeassistant/components/wled/strings.json | Adds new config-flow errors and entity error translation messages for presets/upgrade cases. |
| homeassistant/components/wled/helpers.py | Adds handling for invalid/empty responses and maps them to presets vs generic translation keys. |
| homeassistant/components/wled/coordinator.py | Adds invalid/empty response handling during coordinator updates and adjusts translation mapping for failures. |
| homeassistant/components/wled/config_flow.py | Adds invalid/empty response mapping to config-flow error/abort reasons. |
| translation_key="install_update_wled_error", | ||
| translation_placeholders={"error": str(error)}, | ||
| ) from error | ||
| finally: |
| except (WLEDInvalidResponseError, WLEDEmptyResponseError) as error: | ||
| translation_key = ( | ||
| "invalid_response_presets_wled_error" | ||
| if "presets" in str(error) |
There was a problem hiding this comment.
| pytest.param( | ||
| WLEDInvalidResponseError( | ||
| "Received a non-UTF-8 response from request: GET /json" | ||
| ), | ||
| ConfigEntryState.SETUP_RETRY, | ||
| None, | ||
| "Invalid response from WLED API: ", | ||
| id="invalid_response", | ||
| ), |
| async def test_update_error( | ||
| hass: HomeAssistant, | ||
| mock_wled: MagicMock, | ||
| caplog: pytest.LogCaptureFixture, |
| translation_key = ( | ||
| "invalid_response_presets_wled_error" | ||
| if "presets" in str(error) | ||
| else "invalid_response_wled_error" | ||
| ) | ||
| raise HomeAssistantError( | ||
| translation_domain=DOMAIN, | ||
| translation_key=translation_key, | ||
| translation_placeholders={"error": str(error)}, |
| except (WLEDInvalidResponseError, WLEDEmptyResponseError) as error: | ||
| translation_key = ( | ||
| "invalid_response_presets_wled_error" | ||
| if "presets" in str(error) | ||
| else "invalid_response_wled_error" | ||
| ) |
| except (WLEDInvalidResponseError, WLEDEmptyResponseError) as er: | ||
| if "presets" in str(er): | ||
| errors["base"] = "invalid_response_presets" | ||
| else: | ||
| errors["base"] = "invalid_response" |
| expected_log_message: str, | ||
| caplog: pytest.LogCaptureFixture, | ||
| ) -> None: | ||
| """Ensure entry fails to setup when unsupported version.""" |
| ) | ||
|
|
||
| assert method_mock.call_count == 4 | ||
| assert method_mock.call_count == 5 |
| if "presets" in str(er): | ||
| errors["base"] = "invalid_response_presets" |
There was a problem hiding this comment.
Let's move this into the library, checking if an error string contains a substring is fragile and really nice to handle in the consumer that is Home Assistant.
Breaking change
Proposed change
WLED devices store presets in their internal flash memory (
presets.json). This file is prone to corruption — many users have reported devices where it is damaged or missing. Previously, when the python-wled library tried to fetch presets from such a device, it would propagate low-level exceptions (e.g.UnicodeError) that surfaced as cryptic, unhelpful error messages with no guidance for the user. Related issues: #162199 #163772.The python-wled library (as of frenck/python-wled#2052) now raises typed exceptions -
WLEDInvalidResponseErrorandWLEDEmptyResponseError- for these cases instead of letting raw errors bubble up.This PR catches those exceptions explicitly in:
config_flow.py- during manual setup and Zeroconf discoverycoordinator.py- during periodic data updateshelpers.py- in thewled_exception_handlerdecorator used by entity actions (light, switch, select, number)When the error message indicates the failure is related to
presets, a dedicated, actionable error message is shown:This guides users to the WLED web UI where they can repair or reset their preset configuration. For other invalid response errors, a generic message is shown.
Additionally,
WLEDUpgradeErroris now caught during firmware installation inupdate.py, replacing a previously unhandled exception with a proper translated error message.Type of change
Additional information
Checklist
ruff format homeassistant tests)If user exposed functionality or configuration variables are added/changed:
If the code communicates with devices, web services, or third-party tools:
Updated and included derived files by running:
python3 -m script.hassfest.requirements_all.txt.Updated by running
python3 -m script.gen_requirements_all.To help with the load of incoming pull requests: